home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / glimpse-2.1 / agrep / newmgrep.c < prev    next >
C/C++ Source or Header  |  1995-05-16  |  60KB  |  1,737 lines

  1. /* Copyright (c) 1994 Sun Wu, Udi Manber, Burra Gopal.  All Rights Reserved. */
  2.  
  3. /* multipattern matcher */
  4.  
  5. #include <stdio.h>
  6. #include <ctype.h>
  7. #include "agrep.h"
  8. #include <sys/time.h>
  9. #include <sys/stat.h>
  10.  
  11. #define ddebug
  12. #define uchar unsigned char
  13. #undef    MAXPAT
  14. #define MAXPAT  256
  15. #undef    MAXLINE
  16. #define MAXLINE 1024
  17. #undef    MAXSYM
  18. #define MAXSYM  256
  19. #define MAXMEMBER1 32768
  20. /* #define MAXMEMBER1 262144 */ /*2^18 */ 
  21. #define MAXPATFILE 600000
  22. #define BLOCKSIZE  16384
  23. #define MAXHASH    32768 
  24. /* #define MAXHASH    262144 */
  25. #define mask5        32767
  26. #define max_num    40000
  27. #define W_DELIM       128
  28. #define L_DELIM    10 
  29. #define Hbits 5 /* how much to shift to perform the hash */
  30.  
  31. extern int LIMITOUTPUT;
  32. extern int BYTECOUNT, CurrentByteOffset;
  33. extern int MULTI_OUTPUT;    /* used by glimpse only if OR, never for AND */
  34. extern int DELIMITER;
  35. extern CHAR D_pattern[MaxDelimit];
  36. extern int D_length;
  37. extern CHAR tc_D_pattern[MaxDelimit*2];
  38. extern int tc_D_length;
  39. extern COUNT, FNAME, SILENT, FILENAMEONLY, prev_num_of_matched, num_of_matched;
  40. extern INVERSE, OUTTAIL;
  41. extern WORDBOUND, WHOLELINE, NOUPPER;
  42. extern ParseTree *AParse;
  43. extern int AComplexPattern;
  44. extern unsigned char  CurrentFileName[], Progname[]; 
  45. extern total_line;
  46. extern agrep_initialfd;
  47. extern int EXITONERROR;
  48. extern int PRINTPATTERN;
  49. extern int agrep_inlen;
  50. extern CHAR *agrep_inbuffer;
  51. extern FILE *agrep_finalfp;
  52. extern int agrep_outpointer;
  53. extern int agrep_outlen;
  54. extern CHAR * agrep_outbuffer;
  55. extern int errno;
  56. extern int NEW_FILE, POST_FILTER;
  57.  
  58. extern int tuncompressible();
  59. extern int quick_tcompress();
  60. extern int quick_tuncompress();
  61. extern int TCOMPRESSED;
  62. extern int EASYSEARCH;
  63. extern char FREQ_FILE[MAX_LINE_LEN], HASH_FILE[MAX_LINE_LEN], STRING_FILE[MAX_LINE_LEN];
  64. extern char PAT_FILE_NAME[MAX_LINE_LEN];
  65.  
  66. uchar SHIFT1[MAXMEMBER1];
  67.  
  68. int   LONG  = 0;
  69. int   SHORT = 0;
  70. int   p_size= 0;
  71.  
  72. uchar tr[MAXSYM];
  73. uchar tr1[MAXSYM];
  74. int   HASH[MAXHASH];
  75. int   Hash2[max_num];
  76. uchar *PatPtr[max_num];
  77. uchar *pat_spool = NULL; /* [MAXPATFILE+2*max_num+MAXPAT]; */
  78. uchar *patt[max_num];
  79. int   pat_len[max_num];
  80. int   pat_indices[max_num]; /* pat_indices[p] gives the actual index in matched_teriminals: used only with AParse != 0 */
  81. int num_pat;
  82.  
  83. extern char  amatched_terminals[MAXNUM_PAT]; /* which patterns have been matched in the current line? Used only with AParse != 0, so max_num is not needed */
  84. extern int anum_terminals;
  85. extern int AComplexBoolean;
  86.  
  87. #define DOTCOMPRESSED 1
  88. #if    DOTCOMPRESSED
  89. /* Equivalent variables for compression search */
  90. uchar tc_SHIFT1[MAXMEMBER1];
  91.  
  92. int   tc_LONG  = 0;
  93. int   tc_SHORT = 0;
  94. int   tc_p_size= 0;
  95.  
  96. uchar tc_tr[MAXSYM];
  97. uchar tc_tr1[MAXSYM];
  98. int   tc_HASH[MAXHASH];
  99. int   tc_Hash2[max_num];
  100. uchar *tc_PatPtr[max_num];
  101. uchar *tc_pat_spool = NULL; /* [MAXPATFILE+2*max_num+MAXPAT]; */
  102. uchar *tc_patt[max_num];
  103. int   tc_pat_len[max_num];
  104. int   tc_pat_indices[max_num]; /* pat_indices[p] gives the actual index in matched_teriminals: used only with AParse != 0 */
  105. int tc_num_pat;    /* must be the same as num_pat */
  106. #endif    /*DOTCOMPRESSED*/
  107.  
  108. #ifdef perf_check
  109.     int cshift=0, cshift0=0, chash=0;
  110. #endif
  111.  
  112. /*
  113.  * General idea behind output processing with delimiters, inverse, compression, etc.
  114.  * CAUTION: In compressed files, we can search ONLY for simple patterns or their ;,.
  115.  * Attempts to search for complex patterns / with errors might lead to spurious matches.
  116.  * 1. Once we find the match, go back and forward to get the delimiters that surround
  117.  *    the matched region.
  118.  * 2. If it is a compressed file, verify that the match is "real" (compressed files
  119.  *    can have pseudo matches hence this filtering step is required).
  120.  * 3. Increment num_of_matched.
  121.  * 4. Process some output options which print stuff before the matched region is
  122.  *    printed.
  123.  * 5. If there is compression, decomress and output the matched region. Otherwise
  124.  *    just output it as is. Remember, from step (1) we know the matched region.
  125.  * 6. If inverse is set, then we must keep track of the end of the last matched region
  126.  *    in the variable lastout. When there is a match, we must print everything from
  127.  *    lastout to the beginning of the current matched region (curtextbegin) and then
  128.  *    update lastout to point to the end of the current matched region (curtextend).
  129.  *    ALSO: if we exit from the main loops, we must output everything from the end
  130.  *    of the last matched region to the end of the input buffer.
  131.  * 7. Delimiter handling in complex patterns is different: there the search is done
  132.  *    for a boolean and of the delimiter pattern and the actual pattern.
  133.  * 8. For convenience and speed, the multipattern matching routines to handle
  134.  *    compressed files have been separated from their (normal) counterparts.
  135.  * 9. One special note on handling complicated boolean patterns: the parse
  136.  *    tree will be the same for both compressed and uncomrpessed patterns and the
  137.  *    same amatched_terminals array will be used in both. BUT, the pat_spool and
  138.  *    pat_index, etc., will be different as they refer to the individual terminals.
  139.  */
  140.  
  141. prepf(mfp, mbuf, mlen)
  142. int mfp, mlen;
  143. unsigned char *mbuf;
  144. {
  145.     int length=0, i, p=1;
  146.     uchar *pat_ptr;
  147.     unsigned Mask = 31;
  148.     int num_read;
  149.     unsigned char *buf;
  150.     struct stat stbuf;
  151.     int j, k;    /* to implement \\ */
  152.  
  153.         if ((mfp == -1) && ((mbuf == NULL) || (mlen <= 0))) return -1;
  154.  
  155.     if (mfp != -1) {
  156.         if (fstat(mfp, &stbuf) == -1) {
  157.             fprintf(stderr, "%s: cannot stat file: %s\n", Progname, PAT_FILE_NAME);
  158.             return -1;
  159.         }
  160.         if (!S_ISREG(stbuf.st_mode)) {
  161.             fprintf(stderr, "%s: pattern file not regular file: %s\n", Progname, PAT_FILE_NAME);
  162.             return -1;
  163.         }
  164.         if (stbuf.st_size*2 > MAXPATFILE + 2*max_num) {
  165.             fprintf(stderr, "%s: pattern file too large (> %d B): %s\n", Progname, (MAXPATFILE+2*max_num)/2, PAT_FILE_NAME);
  166.             return -1;
  167.         }
  168.         if (pat_spool != NULL) free(pat_spool);
  169.         pat_ptr = pat_spool = (unsigned char *)malloc(stbuf.st_size*2 + MAXPAT);
  170.         alloc_buf(mfp, &buf, MAXPATFILE+2*BLOCKSIZE);
  171.         while((num_read = fill_buf(mfp, buf+length, 2*BLOCKSIZE)) > 0) {
  172.             length = length + num_read;
  173.             if(length > MAXPATFILE) {
  174.                 fprintf(stderr, "%s: maximum pattern file size is %d\n", Progname, MAXPATFILE);
  175.                                 if (!EXITONERROR) {
  176.                                         errno = 2;
  177.                                         free_buf(mfp, buf);
  178.                                         return -1;
  179.                                 }
  180.                                 else exit(2);
  181.             }
  182.         }
  183.     }
  184.     else {
  185.         buf = mbuf;
  186.         length = mlen;
  187.         if (mlen*2 > MAXPATFILE + 2*max_num) {
  188.             fprintf(stderr, "%s: pattern buffer too large (> %d B)\n", Progname, (MAXPATFILE+2*max_num)/2);
  189.             return -1;
  190.         }
  191.         if (pat_spool != NULL) free(pat_spool);
  192.         pat_ptr = pat_spool = (unsigned char *)malloc(mlen*2 + MAXPAT);
  193.     }
  194.  
  195.     /* Now all the patterns are in buf */
  196.     buf[length] = '\n';
  197.     i=0; p=1;
  198. /* removed by Udi 11/8/94 - we now do WORDBOUND "by hand" 
  199.     if(WORDBOUND) {
  200.         while(i<length) {
  201.             patt[p] = pat_ptr;
  202.             *pat_ptr++ = W_DELIM;
  203.             while((i<length) && ((*pat_ptr = buf[i++]) != '\n')) pat_ptr++;
  204.             *pat_ptr++ = W_DELIM;
  205.             *pat_ptr++ = 0;
  206.             p++;
  207.         }
  208.     }
  209.     else
  210. */
  211.     if(WHOLELINE) {
  212.         while(i<length) {
  213.             patt[p] = pat_ptr;
  214.             *pat_ptr++ = L_DELIM;
  215.             while((i<length) && ((*pat_ptr = buf[i++]) != '\n')) pat_ptr++;
  216.             *pat_ptr++ = L_DELIM;
  217.             *pat_ptr++ = 0;
  218.             p++;
  219.         }
  220.     }
  221.     else {
  222.         while(i < length) {
  223.             patt[p] = pat_ptr;
  224.             while((i<length) && ((*pat_ptr = buf[i++]) != '\n')) pat_ptr++;
  225.             *pat_ptr++ = 0;
  226.             p++;  
  227.         }
  228.     }
  229.  
  230.     /* Now, the patterns have been copied into patt[] */
  231.     if(p>max_num) {
  232.         fprintf(stderr, "%s: maximum number of patterns is %d\n", Progname, max_num); 
  233.                 if (!EXITONERROR) {
  234.                         errno = 2;
  235.                         free_buf(mfp, buf);
  236.                         return -1;
  237.                 }
  238.                 else exit(2);
  239.  
  240.     }
  241.  
  242.     for(i=1; i<20; i++) *pat_ptr = i;  /* boundary safety zone */
  243.  
  244.     /* I might have to keep changing tr s.t. mgrep won't get confused with W_DELIM */
  245.     for(i=0; i< MAXSYM; i++) tr[i] = i;
  246.     if(NOUPPER) {
  247.                 for (i=0; i<MAXSYM; i++)
  248.                         if (isupper(i)) tr[i] = tr[tolower(i)];
  249.         /* for(i='A'; i<= 'Z'; i++) tr[i] = i + 'a' - 'A'; */
  250.     }
  251. /*
  252.     if(WORDBOUND) {
  253.         for(i=1; i<MAXSYM; i++) if(!isalnum(i)) tr[i] = W_DELIM;
  254.     }
  255. removed by Udi 11/8/94 - the trick of using W-delim was too buggy.
  256. we now do it "by hand" after we find a match 
  257. */
  258.     for(i=0; i< MAXSYM; i++) tr1[i] = tr[i]&Mask;
  259.     num_pat =  p-1;
  260.     p_size  =  MAXPAT;
  261.     for(i=1; i<=num_pat; i++) {
  262.         p = strlen(patt[i]);
  263.         if ((patt[i][0] == '^') || (patt[i][0] == '$')) patt[i][0] = '\n';
  264.         if ((p > 1) && ((patt[i][p-1] == '^') || (patt[i][p-1] == '$')) && (patt[i][p-2] != '\\')) patt[i][p-1] = '\n';
  265.  
  266.         /* Added by bg, Dec 2nd 1994 */
  267.         for (k=0; k<p; k++) {
  268.             if (patt[i][k] == '\\') {
  269.                 for (j=k; j<p; j++)
  270.                     patt[i][j] = patt[i][j+1]; /* including '\0' */
  271.                 p--;
  272.             }
  273.         }
  274.  
  275.         pat_len[i] = p;
  276.         /*
  277.         pat_len[i] = (WORDBOUND?(p-2>0?p-2:1):p);  changed by Udi 11/8/94
  278.         */
  279. #ifdef    debug
  280.         printf("prepf(): patt[%d]=%s, pat_len[%d]=%d\n", i, patt[i], i, pat_len[i]);
  281. #endif
  282.         if(p!=0 && p < p_size) p_size = p;    /* MIN */
  283.     }
  284.     if(p_size == 0) {
  285.         fprintf(stderr, "%s: the pattern file is empty\n", Progname);
  286.                 if (!EXITONERROR) {
  287.                         errno = 2;
  288.                         free_buf(mfp, buf);
  289.                         return -1;
  290.                 }
  291.                 else exit(2);
  292.     }
  293.     if(length > 400 && p_size > 2) LONG = 1;
  294.     if(p_size == 1) SHORT = 1;
  295.     for(i=0; i<MAXMEMBER1; i++) SHIFT1[i] = p_size - 1 - LONG;
  296.     for(i=0; i<MAXHASH; i++) {
  297.         HASH[i] = 0;
  298.     }
  299.     for(i=1; i<=num_pat; i++) f_prep(i, patt[i]);
  300.     accumulate();
  301.     memset(pat_indices, '\0', sizeof(int) * (num_pat + 1));
  302.     for(i=1; i<=num_pat; i++) f_prep1(i, patt[i]);
  303.  
  304. #if    DOTCOMPRESSED
  305.     /* prepf for compression */
  306.     if (-1 == tc_prepf(buf, length)) {
  307.         free_buf(mfp, buf);
  308.         return -1;
  309.     }
  310. #endif    /*DOTCOMPRESSED*/
  311.         free_buf(mfp, buf);
  312.         return 0;
  313. }
  314.  
  315. #if    DOTCOMPRESSED
  316. /*
  317.  * Compression equivalent of prepf: called right after prepf.
  318.  * 1. Read patt and SHIFT1
  319.  * 2. Call tcompress on the patterns in patt and put in tc_patt.
  320.  * 3. Use these patterns to compute tc_SHIFT (ignore WDELIM, LDELIM, case sensitivity, etc.)
  321.  * 4. Process other variables/functions (pat_spool, tr, tr1, pat_len, accumulate, SHIFT1, f_prep, f_prep1, pat_indices) appropriately.
  322.  */
  323. tc_prepf(buf, length)
  324. unsigned char *buf;
  325. int    length;
  326. {
  327.     int i, p=1;
  328.     uchar *pat_ptr;
  329.     unsigned Mask = 31;
  330.     int tc_length;
  331.     unsigned char tc_buf[MAXPAT * 2];    /* maximum length of the compressed pattern */
  332.     static struct timeval initt, finalt;
  333.  
  334.     if (length*2 > MAXPATFILE + 2*max_num) {
  335.         fprintf(stderr, "%s: pattern buffer too large (> %d B)\n", Progname, (MAXPATFILE+2*max_num)/2);
  336.         return -1;
  337.     }
  338.     if (tc_pat_spool != NULL) free(tc_pat_spool);
  339.     pat_ptr = tc_pat_spool = (unsigned char *)malloc(length*2 + MAXPAT);
  340.  
  341. #if    MEASURE_TIMES
  342.     gettimeofday(&initt, NULL);
  343. #endif    /*MEASURE_TIMES*/
  344.  
  345.     i=0; p=1;
  346.     while(i < length) {
  347.         tc_patt[p] = pat_ptr;
  348.         while((*pat_ptr = buf[i++]) != '\n') pat_ptr++;
  349.         *pat_ptr++ = 0;
  350.         if ((tc_length = quick_tcompress(FREQ_FILE, HASH_FILE, tc_patt[p], strlen(tc_patt[p]), tc_buf, MAXPAT * 2 - 8, TC_EASYSEARCH)) > 0) {
  351.             memcpy(tc_patt[p], tc_buf, tc_length);
  352.             tc_patt[p][tc_length] = '\0';
  353.             pat_ptr = tc_patt[p] + tc_length + 1;    /* character after '\0' */
  354.         }
  355.         p++;  
  356.     }
  357.  
  358.     for(i=1; i<20; i++) *pat_ptr = i;  /* boundary safety zone */
  359.  
  360.     /* Ignore all other options: it is automatically W_DELIM */
  361.     for(i=0; i< MAXSYM; i++) tc_tr[i] = i;
  362.     for(i=0; i< MAXSYM; i++) tc_tr1[i] = tc_tr[i]&Mask;
  363.     tc_num_pat =  p-1;
  364.     tc_p_size  =  MAXPAT;
  365.     for(i=1; i<=num_pat; i++) {
  366.         p = strlen(tc_patt[i]);
  367.         tc_pat_len[i] = p;
  368. #ifdef    debug
  369.         printf("prepf(): tc_patt[%d]=%s, tc_pat_len[%d]=%d\n", i, tc_patt[i], i, tc_pat_len[i]);
  370. #endif
  371.         if(p!=0 && p < tc_p_size) tc_p_size = p;    /* MIN */
  372.     }
  373.     if(tc_p_size == 0) {    /* cannot happen NOW */
  374.         fprintf(stderr, "%s: the pattern file is empty\n", Progname);
  375.                 if (!EXITONERROR) {
  376.                         errno = 2;
  377.                         return -1;
  378.                 }
  379.                 else exit(2);
  380.     }
  381.     if(length > 400 && tc_p_size > 2) tc_LONG = 1;
  382.     if(tc_p_size == 1) tc_SHORT = 1;
  383.     for(i=0; i<MAXMEMBER1; i++) tc_SHIFT1[i] = tc_p_size - 1 - LONG;
  384.     for(i=0; i<MAXHASH; i++) {
  385.         tc_HASH[i] = 0;
  386.     }
  387.     for(i=1; i<=tc_num_pat; i++) tc_f_prep(i, tc_patt[i]);
  388.     tc_accumulate();
  389.     memset(tc_pat_indices, '\0', sizeof(int) * (tc_num_pat + 1));
  390.     for(i=1; i<=tc_num_pat; i++) tc_f_prep1(i, tc_patt[i]);
  391.  
  392. #if    MEASURE_TIMES
  393.     gettimeofday(&finalt, NULL);
  394.     INFILTER_ms +=  (finalt.tv_sec*1000 + finalt.tv_usec/1000) - (initt.tv_sec*1000 + initt.tv_usec/1000);
  395. #endif    /*MEASURE_TIMES*/
  396.         return 0;
  397. }
  398. #endif    /*DOTCOMPRESSED*/
  399.  
  400.  
  401. mgrep(fd)
  402. int fd;
  403.     register char r_newline = '\n';
  404.     unsigned char *text;
  405.     register int buf_end, num_read, start, end, residue = 0;
  406.     int    oldCurrentByteOffset;
  407.     int    first_time = 1;
  408.  
  409. #if     AGREP_POINTER
  410.         if (fd != -1) {
  411. #endif  /*AGREP_POINTER*/
  412.                 alloc_buf(fd, &text, 2*BLOCKSIZE+MAXLINE);
  413.         text[MAXLINE-1] = '\n';  /* initial case */
  414.         start = MAXLINE;
  415.  
  416.         while( (num_read = fill_buf(fd, text+MAXLINE, 2*BLOCKSIZE)) > 0) 
  417.         {
  418.             buf_end = end = MAXLINE + num_read -1 ;
  419.             oldCurrentByteOffset = CurrentByteOffset;
  420.  
  421.             if (first_time) {
  422.                 if ((TCOMPRESSED == ON) && tuncompressible(text+MAXLINE, num_read)) {
  423.                     EASYSEARCH = text[MAXLINE+SIGNATURE_LEN-1];
  424.                     start += SIGNATURE_LEN;
  425.                     CurrentByteOffset += SIGNATURE_LEN;
  426.                     if (!EASYSEARCH) {
  427.                         fprintf(stderr, "not compressed for easy-search: can miss some matches in: %s\n", CurrentFileName);
  428.                     }
  429.                 }
  430.                 else TCOMPRESSED = OFF;
  431.                 first_time = 0;
  432.             }
  433.  
  434.             if (!DELIMITER) {
  435.                 while(text[end]  != r_newline && end > MAXLINE) end--;
  436.                 text[start-1] = r_newline;
  437.             }
  438.             else {
  439.                 unsigned char *newbuf = text + end + 1;
  440.                 newbuf = backward_delimiter(newbuf, text+MAXLINE, D_pattern, D_length, OUTTAIL);    /* see agrep.c/'d' */
  441.                 if (newbuf < text+MAXLINE+D_length) newbuf = text + end + 1;
  442.                 end = newbuf - text - 1;
  443.                 memcpy(text+start-D_length, D_pattern, D_length);
  444.             }
  445.             residue = buf_end - end  + 1 ;
  446.             if(INVERSE && COUNT) countline(text+MAXLINE, num_read);
  447.  
  448.             /* MGREP_PROCESS */
  449.             if (TCOMPRESSED) {    /* separate functions since separate globals => too many if-statements within a single function makes it slow */
  450. #if    DOTCOMPRESSED
  451.                 if(tc_SHORT) { if (-1 == tc_m_short(text, start, end)) {free_buf(fd, text); return -1;}}
  452.                 else      { if (-1 == tc_monkey1(text, start, end)) {free_buf(fd, text); return -1;}}
  453. #endif    /*DOTCOMPRESSED*/
  454.             }
  455.             else {
  456.                 if(SHORT) { if (-1 == m_short(text, start, end)) {free_buf(fd, text); return -1;}}
  457.                 else      { if (-1 == monkey1(text, start, end)) {free_buf(fd, text); return -1;}}
  458.             }
  459.                         if(FILENAMEONLY && (num_of_matched - prev_num_of_matched) && (NEW_FILE || !POST_FILTER)) {
  460.                                 if (agrep_finalfp != NULL)
  461.                                         fprintf(agrep_finalfp, "%s\n", CurrentFileName);
  462.                                 else {
  463.                                         int outindex;
  464.                                         for(outindex=0; (outindex+agrep_outpointer<agrep_outlen) &&
  465.                                                         (CurrentFileName[outindex] != '\0'); outindex++) {
  466.                                                 agrep_outbuffer[agrep_outpointer+outindex] = CurrentFileName[outindex];
  467.                                         }
  468.                                         if ((CurrentFileName[outindex] != '\0') || (outindex+agrep_outpointer+1>=agrep_outlen)) {
  469.                                                 OUTPUT_OVERFLOW;
  470.                                                 free_buf(fd, text);
  471.                                                 return -1;
  472.                                         }
  473.                                         else {
  474.                                                 agrep_outbuffer[agrep_outpointer+outindex++] = '\n';
  475.                                         }
  476.                                         agrep_outpointer += outindex;
  477.                                 }
  478.                                 free_buf(fd, text);
  479.                                 NEW_FILE = OFF;
  480.                                 return 0;
  481.                         }
  482.  
  483.             CurrentByteOffset = oldCurrentByteOffset + end - start + 1;
  484.             start = MAXLINE - residue;
  485.             if(start < 0) {
  486.                 start = 1; 
  487.             }
  488.             strncpy(text+start, text+end, residue);
  489.  
  490.             if ((LIMITOUTPUT > 0) && (LIMITOUTPUT <= num_of_matched)) {
  491.                 free_buf(fd, text);
  492.                 return 0;    /* done */
  493.             }
  494.         } /* end of while(num_read = ... */
  495.         if (!DELIMITER) {
  496.             text[start-1] = '\n';
  497.             text[MAXLINE] = '\n';
  498.         }
  499.         else {
  500.             if (start > D_length) memcpy(text+start-D_length, D_pattern, D_length);
  501.             memcpy(text+MAXLINE, D_pattern, D_length);
  502.         }
  503.         end = start + residue;
  504.         if(residue > 1) {
  505.             if (TCOMPRESSED) {
  506. #if    DOTCOMPRESSED
  507.                 if(tc_SHORT) tc_m_short(text, start, end);
  508.                 else      tc_monkey1(text, start, end);
  509. #endif    /*DOTCOMPRESSED*/
  510.             }
  511.             else {
  512.                 if(SHORT) m_short(text, start, end);
  513.                 else      monkey1(text, start, end);
  514.             }
  515.                         if(FILENAMEONLY && (num_of_matched - prev_num_of_matched) && (NEW_FILE || !POST_FILTER)) {
  516.                                 if (agrep_finalfp != NULL)
  517.                                         fprintf(agrep_finalfp, "%s\n", CurrentFileName);
  518.                                 else {
  519.                                         int outindex;
  520.                                         for(outindex=0; (outindex+agrep_outpointer<agrep_outlen) &&
  521.                                                         (CurrentFileName[outindex] != '\0'); outindex++) {
  522.                                                 agrep_outbuffer[agrep_outpointer+outindex] = CurrentFileName[outindex];
  523.                                         }
  524.                                         if ((CurrentFileName[outindex] != '\0') || (outindex+agrep_outpointer+1>=agrep_outlen)) {
  525.                                                 OUTPUT_OVERFLOW;
  526.                                                 free_buf(fd, text);
  527.                                                 return -1;
  528.                                         }
  529.                                         else {
  530.                                                 agrep_outbuffer[agrep_outpointer+outindex++] = '\n';
  531.                                         }
  532.                                         agrep_outpointer += outindex;
  533.                                 }
  534.                                 free_buf(fd, text);
  535.                                 NEW_FILE = OFF;
  536.                                 return 0;
  537.                         }
  538.         }
  539.         free_buf(fd, text);
  540.         return (0);
  541. #if    AGREP_POINTER
  542.     }
  543.     else {
  544.                 text = (unsigned char *)agrep_inbuffer;
  545.                 num_read = agrep_inlen;
  546.                 start = 1;
  547.                 buf_end = end = num_read - 1;
  548.  
  549.             oldCurrentByteOffset = CurrentByteOffset;
  550.  
  551.             if (first_time) {
  552.                 if ((TCOMPRESSED == ON) && tuncompressible(text+MAXLINE, num_read)) {
  553.                     EASYSEARCH = text[MAXLINE+SIGNATURE_LEN-1];
  554.                     start += SIGNATURE_LEN;
  555.                     CurrentByteOffset += SIGNATURE_LEN;
  556.                     if (!EASYSEARCH) {
  557.                         fprintf(stderr, "not compressed for easy-search: can miss some matches in: %s\n", CurrentFileName);
  558.                     }
  559.                 }
  560.                 else TCOMPRESSED = OFF;
  561.                 first_time = 0;
  562.             }
  563.  
  564.             if (!DELIMITER)
  565.                 while(text[end]  != r_newline && end > 1) end--;
  566.             else {
  567.                                 unsigned char *newbuf = text + end + 1;
  568.                                 newbuf = backward_delimiter(newbuf, text, D_pattern, D_length, OUTTAIL);        /* see agrep.c/'d' */
  569.                 if (newbuf < text+D_length) newbuf = text + end + 1;
  570.                                 end = newbuf - text - 1;
  571.             }
  572.             /* text[0] = text[end] = r_newline; : the user must ensure that the delimiter is there at text[0] and occurs somewhere before text[end] */
  573.  
  574.             if (INVERSE && COUNT) countline(text, num_read);
  575.  
  576.                         /* An exact copy of the above MGREP_PROCESS */
  577.             if (TCOMPRESSED) {    /* separate functions since separate globals => too many if-statements within a single function makes it slow */
  578. #if    DOTCOMPRESSED
  579.                 if(tc_SHORT) { if (-1 == tc_m_short(text, start, end)) {free_buf(fd, text); return -1;}}
  580.                 else      { if (-1 == tc_monkey1(text, start, end)) {free_buf(fd, text); return -1;}}
  581. #endif    /*DOTCOMPRESSED*/
  582.             }
  583.             else {
  584.                 if(SHORT) { if (-1 == m_short(text, start, end)) {free_buf(fd, text); return -1;}}
  585.                 else      { if (-1 == monkey1(text, start, end)) {free_buf(fd, text); return -1;}}
  586.             }
  587.                         if(FILENAMEONLY && (num_of_matched - prev_num_of_matched) && (NEW_FILE || !POST_FILTER)) {
  588.                                 if (agrep_finalfp != NULL)
  589.                                         fprintf(agrep_finalfp, "%s\n", CurrentFileName);
  590.                                 else {
  591.                                         int outindex;
  592.                                         for(outindex=0; (outindex+agrep_outpointer<agrep_outlen) &&
  593.                                                         (CurrentFileName[outindex] != '\0'); outindex++) {
  594.                                                 agrep_outbuffer[agrep_outpointer+outindex] = CurrentFileName[outindex];
  595.                                         }
  596.                                         if ((CurrentFileName[outindex] != '\0') || (outindex+agrep_outpointer+1>=agrep_outlen)) {
  597.                                                 OUTPUT_OVERFLOW;
  598.                                                 free_buf(fd, text);
  599.                                                 return -1;
  600.                                         }
  601.                                         else {
  602.                                                 agrep_outbuffer[agrep_outpointer+outindex++] = '\n';
  603.                                         }
  604.                                         agrep_outpointer += outindex;
  605.                                 }
  606.                                 free_buf(fd, text);
  607.                                 NEW_FILE = OFF;
  608.                                 return 0;
  609.                         }
  610.  
  611.                 return 0;
  612.     }
  613. #endif    /*AGREP_POINTER*/
  614. #ifdef perf_check
  615.     fprintf(stderr,"Shifted %d times; shift=0 %d times; hash was = %d times\n",cshift, cshift0, chash);
  616.     return 0;
  617. #endif
  618. } /* end mgrep */
  619.  
  620. countline(text, len)
  621. unsigned char *text; int len;
  622. {
  623. int i;
  624.     for (i=0; i<len; i++) if(text[i] == '\n') total_line++;
  625. }
  626.  
  627. /* Stuff that always needs to be printed whenever there is a match in all functions in this file */
  628. print_options(pat_index)
  629.     int    pat_index;
  630. {
  631.     if(FNAME && (NEW_FILE || !POST_FILTER)) {
  632.         char    nextchar = (POST_FILTER == ON)?'\n':' ';
  633.         char    *prevstring = (POST_FILTER == ON)?"\n":"";
  634.         if (agrep_finalfp != NULL)
  635.             fprintf(agrep_finalfp, "%s%s:%c", prevstring, CurrentFileName, nextchar);
  636.         else {
  637.             int outindex;
  638.             if (prevstring[0] != '\0') {
  639.                 if(agrep_outpointer + 1 >= agrep_outlen) {
  640.                     OUTPUT_OVERFLOW;
  641.                     return -1;
  642.                 }
  643.                 else agrep_outbuffer[agrep_outpointer ++] = prevstring[0];
  644.             }
  645.             for(outindex=0; (outindex+agrep_outpointer<agrep_outlen) &&
  646.                     (CurrentFileName[outindex] != '\0'); outindex++) {
  647.                 agrep_outbuffer[agrep_outpointer+outindex] = CurrentFileName[outindex];
  648.             }
  649.             if ((CurrentFileName[outindex] != '\0') || (outindex+agrep_outpointer+2>=agrep_outlen)) {
  650.                 OUTPUT_OVERFLOW;
  651.                 return -1;
  652.             }
  653.             else {
  654.                 agrep_outbuffer[agrep_outpointer+outindex++] = ':';
  655.                 agrep_outbuffer[agrep_outpointer+outindex++] = nextchar;
  656.             }
  657.             agrep_outpointer += outindex;
  658.         }
  659.         NEW_FILE = OFF;
  660.     }
  661.  
  662.     if (PRINTPATTERN) {
  663.         if (agrep_finalfp != NULL)
  664.             fprintf(agrep_finalfp, "%d- ", pat_index);
  665.         else {
  666.             char s[32];
  667.             int outindex;
  668.             sprintf(s, "%d- ", pat_index);
  669.             for(outindex=0; (outindex+agrep_outpointer<agrep_outlen) &&
  670.                     (s[outindex] != '\0'); outindex++) {
  671.                 agrep_outbuffer[agrep_outpointer+outindex] = s[outindex];
  672.             }
  673.             if (s[outindex] != '\0') {
  674.                 OUTPUT_OVERFLOW;
  675.                 return -1;
  676.             }
  677.             agrep_outpointer += outindex;
  678.         }
  679.     }
  680.  
  681.     if (BYTECOUNT) {
  682.         if (agrep_finalfp != NULL)
  683.             fprintf(agrep_finalfp, "%d= ", CurrentByteOffset);
  684.         else {
  685.             char s[32];
  686.             int outindex;
  687.             sprintf(s, "%d= ", CurrentByteOffset);
  688.             for(outindex=0; (outindex+agrep_outpointer<agrep_outlen) &&
  689.                     (s[outindex] != '\0'); outindex++) {
  690.                 agrep_outbuffer[agrep_outpointer+outindex] = s[outindex];
  691.             }
  692.             if (s[outindex] != '\0') {
  693.                 OUTPUT_OVERFLOW;
  694.                 return -1;
  695.             }
  696.             agrep_outpointer += outindex;
  697.         }
  698.     }
  699. }
  700.  
  701. monkey1( text, start, end  ) 
  702. int start, end; register unsigned char *text;
  703. {
  704.         unsigned char *oldtext;
  705.     int pat_index;
  706.     register uchar *textend;
  707.     unsigned char *textbegin;
  708.     unsigned char *curtextend;
  709.     unsigned char *curtextbegin;
  710.     register unsigned hash;
  711.     register uchar shift;
  712.     register int  m1, Long=LONG;
  713.     int MATCHED=0;
  714.     register uchar *qx;
  715.     register uchar *px;
  716.     register int p, p_end;
  717.     uchar *lastout;
  718.     /* int OUT=0; */
  719.     int hash2;
  720.     int j;
  721.     int DOWITHMASK;
  722.  
  723.     DOWITHMASK = 0;
  724.     if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  725.     textbegin = text + start;
  726.     textend = text + end;
  727.     m1 = p_size-1;
  728.     lastout = text+start;
  729.     text = text + start + m1 -1 ;
  730.     /* -1 to allow match to the first \n in case the pattern has ^ in front of it */
  731. /*
  732.     if (WORDBOUND || WHOLELINE) text = text-1;
  733.     if (WHOLELINE) text = text-1;
  734. */
  735.         /* to accomodate the extra 2 W_delim */
  736.     while (text <= textend) {
  737.         hash=tr1[*text];
  738.         hash=(hash<<Hbits)+(tr1[*(text-1)]);
  739.         if(Long) hash=(hash<<Hbits)+(tr1[*(text-2)]);
  740.         shift = SHIFT1[hash];
  741. #ifdef perf_check
  742.         cshift++;
  743. #endif
  744.         if(shift == 0) {
  745.             hash=hash&mask5;
  746.             hash2 = (tr[*(text-m1)]<<8) + tr[*(text-m1+1)];
  747.             p = HASH[hash];
  748. #ifdef perf_check
  749.             cshift0++;
  750. #endif
  751.             p_end = HASH[hash+1];
  752. #ifdef debug
  753.             printf("hash=%d, p=%d, p_end=%d\n", hash, p, p_end);
  754. #endif
  755.             while(p++ < p_end) {
  756.                 if(hash2 != Hash2[p]) continue;
  757. #ifdef perf_check
  758.                 chash++;
  759. #endif
  760.                 if (((pat_index = pat_indices[p]) <= 0) || (pat_len[pat_index] <= 0)) continue;
  761.                 px = PatPtr[p];
  762.                 qx = text-m1;
  763.                 while((*px!=0)&&(tr[*px] == tr[*qx])) {
  764.                     px++;
  765.                     qx++;
  766.                 }
  767.                 if (*px == 0) {
  768.                     if(text > textend) return;
  769.                     if (WORDBOUND) {
  770.                         if (isalnum(*qx)) goto skip_output;
  771.                         if (isalnum(*(text-m1-1))) goto skip_output;
  772.                     }
  773.                     if (!DOWITHMASK) {
  774.                                                 /* Don't update CurrentByteOffset here: only before outputting properly */
  775.                                                 if (!DELIMITER) {
  776.                             curtextbegin = text; while((curtextbegin > textbegin) && (*(--curtextbegin) != '\n'));
  777.                             if (*curtextbegin == '\n') curtextbegin ++;
  778.                             curtextend = text+1; while((curtextend < textend) && (*curtextend != '\n')) curtextend ++;
  779.                             if (*curtextend == '\n') curtextend ++;
  780.                                                 }
  781.                                                 else {
  782.                                                         curtextbegin = backward_delimiter(text, textbegin, D_pattern, D_length, OUTTAIL);
  783.                                                         curtextend = forward_delimiter(text+1, textend, D_pattern, D_length, OUTTAIL);
  784.                                                 }
  785.                         if (!OUTTAIL || INVERSE) textbegin = curtextend;
  786.                         else if (DELIMITER) textbegin = curtextend - D_length;
  787.                         else textbegin = curtextend - 1;
  788.                     }
  789.  
  790.                     DOWITHMASK = 1;
  791.                     amatched_terminals[pat_index - 1] = 1;
  792.                     if (AComplexBoolean) {
  793.                         /* Can output only after all the matches in the current record have been identified: just like filter_output */
  794.                         oldtext = text;
  795.                         CurrentByteOffset += (oldtext + pat_len[pat_index] - 1 - text);
  796.                         text = oldtext + pat_len[pat_index] - 1;
  797.                         MATCHED = 0;
  798.                         goto skip_output;
  799.                     }
  800.                     else if ((long)AParse & AND_EXP) {
  801.                         for (j=0; j<anum_terminals; j++) if (!amatched_terminals[j]) break;
  802.                         if (j<anum_terminals) goto skip_output;
  803.                     }
  804.                     MATCHED=1;
  805.                                         oldtext = text; /* only for MULTI_OUTPUT */
  806.  
  807. #undef    DO_OUTPUT
  808. #define DO_OUTPUT(change_text)\
  809.                     num_of_matched++;\
  810.                     if(FILENAMEONLY || SILENT)  return;\
  811.                     if (!COUNT) {\
  812.                         print_options(pat_index);\
  813.                         if(!INVERSE) {\
  814.                             if (agrep_finalfp != NULL) {\
  815.                                 fwrite(curtextbegin, 1, curtextend - curtextbegin, agrep_finalfp);\
  816.                             }\
  817.                             else {\
  818.                                 if (agrep_outpointer + curtextend - curtextbegin>= agrep_outlen) {\
  819.                                     OUTPUT_OVERFLOW;\
  820.                                     return -1;\
  821.                                 }\
  822.                                 else {\
  823.                                     memcpy(agrep_outbuffer + agrep_outpointer, curtextbegin, curtextend-curtextbegin);\
  824.                                     agrep_outpointer += curtextend - curtextbegin;\
  825.                                 }\
  826.                             }\
  827.                                                         if ((change_text) && MULTI_OUTPUT) {     /* next match starting from end of current */\
  828.                                 CurrentByteOffset += (oldtext + pat_len[pat_index] - 1 - text);\
  829.                                                                 text = oldtext + pat_len[pat_index] - 1;\
  830.                                                                 MATCHED = 0;\
  831.                                                         }\
  832.                             else if (change_text) {\
  833.                                 CurrentByteOffset += textbegin - text;\
  834.                                 text = textbegin;\
  835.                             }\
  836.                         }\
  837.                         else {    /* INVERSE */\
  838.                             /* if(lastout < curtextbegin) OUT=1; */\
  839.                             if (agrep_finalfp != NULL)\
  840.                                 fwrite(lastout, 1, curtextbegin-lastout, agrep_finalfp);\
  841.                             else {\
  842.                                 if (curtextbegin - lastout + agrep_outpointer >= agrep_outlen) {\
  843.                                     OUTPUT_OVERFLOW;\
  844.                                     return -1;\
  845.                                 }\
  846.                                 memcpy(agrep_outbuffer+agrep_outpointer, lastout, curtextbegin-lastout);\
  847.                                 agrep_outpointer += (curtextbegin-lastout);\
  848.                             }\
  849.                             lastout=textbegin;\
  850.                             if (change_text) {\
  851.                                 CurrentByteOffset += textbegin - text;\
  852.                                 text = textbegin;\
  853.                             }\
  854.                         }\
  855.                     }\
  856.                     else if (change_text) {    /* COUNT */\
  857.                         CurrentByteOffset += textbegin - text;\
  858.                         text = textbegin;\
  859.                     }\
  860.                     if ((LIMITOUTPUT > 0) && (LIMITOUTPUT <= num_of_matched)) return 0;    /* done */\
  861.  
  862.                     DO_OUTPUT(1)
  863.                 }
  864.  
  865.             skip_output:
  866.                                 if (MATCHED && !MULTI_OUTPUT && !AComplexBoolean) break;    /* else look for more possible matches since we never know how many will match */
  867.                 if (DOWITHMASK && (text >= curtextend - 1)) {
  868.                     DOWITHMASK = 0;
  869.                     if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  870.                         DO_OUTPUT(0)
  871.                     }
  872.                     if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  873.                 }
  874.             }
  875.             /* If I found some match and I am about to cross over a delimiter, then set DOWITHMASK to 0 and zero out the amatched_terminals */
  876.             if (DOWITHMASK && (text >= curtextend - 1)) {
  877.                 DOWITHMASK = 0;
  878.                 if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  879.                     DO_OUTPUT(0)
  880.                 }
  881.                 if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  882.             }
  883.             if(!MATCHED) shift = 1;    /* || MULTI_OUTPUT is implicit */
  884.             else {
  885.                 MATCHED = 0;
  886.                 shift = m1 - 1 > 0 ? m1 - 1 : 1;
  887.             }
  888.         }
  889.  
  890.         /* If I found some match and I am about to cross over a delimiter, then set DOWITHMASK to 0 and zero out the amatched_terminals */
  891.         if (DOWITHMASK && (text >= curtextend - 1)) {
  892.             DOWITHMASK = 0;
  893.             if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  894.                 DO_OUTPUT(0)
  895.             }
  896.             if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  897.         }
  898.  
  899.         text += shift;
  900.         CurrentByteOffset += shift;
  901.     }
  902.  
  903.     /* Do residual stuff: check if there was a match at the end of the line | check if rest of the buffer needs to be output due to inverse */
  904.  
  905.     if (DOWITHMASK && (text >= curtextend - 1)) {
  906.         DOWITHMASK = 0;
  907.         if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  908.             DO_OUTPUT(0)
  909.         }
  910.         if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  911.     }
  912.  
  913.     if(INVERSE && !COUNT && (lastout <= textend)) {
  914.                 if (agrep_finalfp != NULL) {
  915.                         while(lastout <= textend) fputc(*lastout++, agrep_finalfp);
  916.                 }
  917.                 else {
  918.                         if (textend - lastout + 1 + agrep_outpointer >= agrep_outlen) {
  919.                                 OUTPUT_OVERFLOW;
  920.                                 return -1;
  921.                         }
  922.                         memcpy(agrep_outbuffer+agrep_outpointer, lastout, textend-lastout+1);
  923.                         agrep_outpointer += (textend-lastout+1);
  924.                         lastout = textend;
  925.                 }
  926.     }
  927.  
  928.     return 0;
  929. }
  930.  
  931. #if    DOTCOMPRESSED
  932. tc_monkey1( text, start, end  ) 
  933. int start, end;
  934. register unsigned char *text;
  935. {
  936.         unsigned char *oldtext;
  937.     int pat_index;
  938.     register uchar *textend;
  939.     unsigned char *textbegin;
  940.     unsigned char *curtextend;
  941.         unsigned char *curtextbegin;
  942.     register unsigned hash;
  943.     register uchar shift;
  944.     register int  m1, Long=LONG;
  945.     int MATCHED=0;
  946.     register uchar *qx;
  947.     register uchar *px;
  948.     register int p, p_end;
  949.     uchar *lastout;
  950.     /* int OUT=0; */
  951.     int hash2;
  952.     int j;
  953.     int DOWITHMASK;
  954.     struct timeval initt, finalt;
  955.     int newlen;
  956.  
  957.     DOWITHMASK = 0;
  958.     if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  959.     textbegin = text + start;
  960.     textend = text + end;
  961.     m1 = tc_p_size-1;
  962.     lastout = text+start;
  963.     text = text + start + m1 -1;
  964.     /* -1 to allow match to the first \n in case the pattern has ^ in front of it */
  965.     /* WORDBOUND adjustment not required */
  966.     while (text <= textend) {
  967.         hash=tc_tr1[*text];
  968.         hash=(hash<<Hbits)+(tc_tr1[*(text-1)]);
  969.         if(Long) hash=(hash<<Hbits)+(tc_tr1[*(text-2)]);
  970.         shift = tc_SHIFT1[hash];
  971. #ifdef perf_check
  972.         cshift++;
  973. #endif
  974.         if(shift == 0) {
  975.             hash=hash&mask5;
  976.             hash2 = (tc_tr[*(text-m1)]<<8) + tc_tr[*(text-m1+1)];
  977.             p = tc_HASH[hash];
  978. #ifdef perf_check
  979.             cshift0++;
  980. #endif
  981.             p_end = tc_HASH[hash+1];
  982. #ifdef debug
  983.             printf("hash=%d, p=%d, p_end=%d\n", hash, p, p_end);
  984. #endif
  985.             while(p++ < p_end) {
  986.                 if(hash2 != tc_Hash2[p]) continue;
  987. #ifdef perf_check
  988.                 chash++;
  989. #endif
  990.                 if (((pat_index = tc_pat_indices[p]) <= 0) || (tc_pat_len[pat_index] <= 0)) continue;
  991.                 px = tc_PatPtr[p];
  992.                 qx = text-m1;
  993.  
  994.                  while((*px!=0)&&(tc_tr[*px] == tc_tr[*qx])) {
  995.                      px++;
  996.                      qx++;
  997.                  }
  998.                  if (*px == 0) {
  999.                     if(text > textend) return;
  1000.                     if (!DOWITHMASK) {
  1001.                         /* Don't update CurrentByteOffset here: only before outputting properly */
  1002.                         if (!DELIMITER) {
  1003.                             curtextbegin = text; while((curtextbegin > textbegin) && (*(--curtextbegin) != '\n'));
  1004.                             if (*curtextbegin == '\n') curtextbegin ++;
  1005.                             curtextend = text+1; while((curtextend < textend) && (*curtextend != '\n')) curtextend ++;
  1006.                             if (*curtextend == '\n') curtextend ++;
  1007.                         }
  1008.                         else {
  1009.                             curtextbegin = backward_delimiter(text, textbegin, tc_D_pattern, tc_D_length, OUTTAIL);
  1010.                             curtextend = forward_delimiter(text+1, textend, tc_D_pattern, tc_D_length, OUTTAIL);
  1011.                         }
  1012.                     }
  1013.                     /* else prev curtextbegin is OK: if full AND isn't found, DOWITHMASK is 0-ed so that we search at most 1 line below */
  1014. #if    MEASURE_TIMES
  1015.                     gettimeofday(&initt, NULL);
  1016. #endif    /*MEASURE_TIMES*/
  1017.                     /* Was it really a match in the compressed line from prev line in text to text + strlen(tc_pat_len[pat_index]? */
  1018.                     if (-1==exists_tcompressed_word(tc_PatPtr[p], tc_pat_len[pat_index], curtextbegin, text - curtextbegin + tc_pat_len[pat_index], EASYSEARCH))
  1019.                         goto skip_output;
  1020. #if     MEASURE_TIMES
  1021.                     gettimeofday(&finalt, NULL);
  1022.                     FILTERALGO_ms +=  (finalt.tv_sec *1000 + finalt.tv_usec/1000) - (initt.tv_sec*1000 + initt.tv_usec/1000);
  1023. #endif  /*MEASURE_TIMES*/
  1024.                     if (!DOWITHMASK) {
  1025.                         if (!OUTTAIL || INVERSE) textbegin = curtextend;
  1026.                         else if (DELIMITER) textbegin = curtextend - D_length;
  1027.                         else textbegin = curtextend - 1;
  1028.                     }
  1029.                     DOWITHMASK = 1;
  1030.                     amatched_terminals[pat_index-1] = 1;
  1031.                     if (AComplexBoolean) {
  1032.                         /* Can output only after all the matches in the current record have been identified: just like filter_output */
  1033.                         oldtext = text;
  1034.                         CurrentByteOffset += (oldtext + pat_len[pat_index] - 1 - text);
  1035.                         text = oldtext + pat_len[pat_index] - 1;
  1036.                         MATCHED = 0;
  1037.                         goto skip_output;
  1038.                     }
  1039.                     else if ((long)AParse & AND_EXP) {
  1040.                         for (j=0; j<anum_terminals; j++) if (!amatched_terminals[j]) break;
  1041.                         if (j<anum_terminals) goto skip_output;
  1042.                     }
  1043.  
  1044.                     MATCHED=1;
  1045.                                         oldtext = text; /* only for MULTI_OUTPUT */
  1046.  
  1047. #undef    DO_OUTPUT
  1048. #define DO_OUTPUT(change_text)\
  1049.                     num_of_matched++;\
  1050.                     if(FILENAMEONLY || SILENT)  return;\
  1051.                     if (!COUNT) {\
  1052.                         print_options(pat_index);\
  1053.                         if(!INVERSE) {\
  1054. /* #if     MEASURE_TIMES\
  1055.                             gettimeofday(&initt, NULL);\
  1056. #endif  MEASURE_TIMES */\
  1057.                             if (agrep_finalfp != NULL)\
  1058.                                 newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, curtextbegin, curtextend-curtextbegin, agrep_finalfp, -1, EASYSEARCH);\
  1059.                             else {\
  1060.                                 if ((newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, curtextbegin, curtextend-curtextbegin, agrep_outbuffer, agrep_outlen - agrep_outpointer, EASYSEARCH)) > 0) {\
  1061.                                     if (newlen + agrep_outpointer >= agrep_outlen) {\
  1062.                                         OUTPUT_OVERFLOW;\
  1063.                                         return -1;\
  1064.                                     }\
  1065.                                     agrep_outpointer += newlen;\
  1066.                                 }\
  1067.                             }\
  1068. /* #if     MEASURE_TIMES\
  1069.                             gettimeofday(&finalt, NULL);\
  1070.                             OUTFILTER_ms += (finalt.tv_sec* 1000 + finalt.tv_usec/1000) - (initt.tv_sec*1000 + initt.tv_usec/1000);\
  1071. #endif  MEASURE_TIMES */\
  1072.                                                         if ((change_text) && MULTI_OUTPUT) {     /* next match starting from end of current */\
  1073.                                 CurrentByteOffset += (oldtext + tc_pat_len[pat_index] - 1 - text);\
  1074.                                                                 text = oldtext + tc_pat_len[pat_index] - 1;\
  1075.                                                                 MATCHED = 0;\
  1076.                                                         }\
  1077.                             else if (change_text) {\
  1078.                                 CurrentByteOffset += textbegin - text;\
  1079.                                 text = textbegin;\
  1080.                             }\
  1081.                         }\
  1082.                         else {    /* INVERSE: Don't care about filtering time */\
  1083.                             /* if(lastout < curtextbegin) OUT=1; */\
  1084.                             if (agrep_finalfp != NULL)\
  1085.                                 newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, lastout, curtextbegin - lastout, agrep_finalfp, -1, EASYSEARCH);\
  1086.                             else {\
  1087.                                 if ((newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, lastout, curtextbegin - lastout, agrep_outbuffer, agrep_outlen - agrep_outpointer, EASYSEARCH)) > 0) {\
  1088.                                     if (newlen + agrep_outpointer >= agrep_outlen) {\
  1089.                                         OUTPUT_OVERFLOW;\
  1090.                                         return -1;\
  1091.                                     }\
  1092.                                     agrep_outpointer += newlen;\
  1093.                                 }\
  1094.                             }\
  1095.                             lastout=textbegin;\
  1096.                             if (change_text) {\
  1097.                                 CurrentByteOffset += textbegin - text;\
  1098.                                 text = textbegin;\
  1099.                             }\
  1100.                         }\
  1101.                     }\
  1102.                     else if (change_text) {\
  1103.                         CurrentByteOffset += textbegin - text;\
  1104.                         text = textbegin;\
  1105.                     }\
  1106.                     if ((LIMITOUTPUT > 0) && (LIMITOUTPUT <= num_of_matched)) return 0;    /* done */\
  1107.  
  1108.                     DO_OUTPUT(1)
  1109.                 }
  1110.  
  1111.             skip_output:
  1112.                                 if (MATCHED && !MULTI_OUTPUT && !AComplexBoolean) break;    /* else look for more possible matches since we never know how many will match */
  1113.                 if (DOWITHMASK && (text >= curtextend - 1)) {
  1114.                     DOWITHMASK = 0;
  1115.                     if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  1116.                         DO_OUTPUT(0)
  1117.                     }
  1118.                     if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1119.                 }
  1120.             }
  1121.             /* If I found some match and I am about to cross over a delimiter, then set DOWITHMASK to 0 and zero out the amatched_terminals */
  1122.             if (DOWITHMASK && (text >= curtextend - 1)) {
  1123.                 DOWITHMASK = 0;
  1124.                 if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  1125.                     DO_OUTPUT(0)
  1126.                 }
  1127.                 if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1128.             }
  1129.             if(!MATCHED) shift = 1;    /* || MULTI_OUTPUT is implicit */
  1130.             else {
  1131.                 MATCHED = 0;
  1132.                 shift = m1 - 1 > 0 ? m1 - 1 : 1;
  1133.             }
  1134.         }
  1135.  
  1136.         /* If I found some match and I am about to cross over a delimiter, then set DOWITHMASK to 0 and zero out the amatched_terminals */
  1137.         if (DOWITHMASK && (text >= curtextend - 1)) {
  1138.             DOWITHMASK = 0;
  1139.             if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  1140.                 DO_OUTPUT(0)
  1141.             }
  1142.             if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1143.         }
  1144.  
  1145.         text += shift;
  1146.         CurrentByteOffset += shift;
  1147.     }
  1148.  
  1149.     /* Do residual stuff: check if there was a match at the end of the line | check if rest of the buffer needs to be output due to inverse */
  1150.  
  1151.     if (DOWITHMASK && (text >= curtextend - 1)) {
  1152.         DOWITHMASK = 0;
  1153.         if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  1154.             DO_OUTPUT(0)
  1155.         }
  1156.         if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1157.     }
  1158.  
  1159.     if (INVERSE && !COUNT && (lastout <= textend)) {
  1160.         if (agrep_finalfp != NULL)
  1161.             newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, lastout, textend - lastout + 1, agrep_finalfp, -1, EASYSEARCH);
  1162.         else {
  1163.             if ((newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, lastout, textend - lastout + 1, agrep_outbuffer, agrep_outlen - agrep_outpointer, EASYSEARCH)) > 0) {
  1164.                 if (newlen + agrep_outpointer >= agrep_outlen) {
  1165.                     OUTPUT_OVERFLOW;
  1166.                     return -1;
  1167.                 }
  1168.                 agrep_outpointer += newlen;
  1169.             }
  1170.         }
  1171.     }
  1172.  
  1173.     return 0;
  1174. }
  1175. #endif    /*DOTCOMPRESSED*/
  1176.  
  1177. /* shift is always 1: slight change in MATCHED semantics: it is set to 1 even if COUNT is set: previously, it wasn't set. Will it effect m_short? */
  1178. m_short(text, start, end)
  1179. int start, end; register uchar *text;
  1180. {
  1181.     int pat_index;
  1182.         unsigned char *oldtext;
  1183.     register uchar *textend;
  1184.     unsigned char *textbegin;
  1185.     unsigned char *curtextend;
  1186.     unsigned char *curtextbegin;
  1187.     register int p, p_end;
  1188.     int MATCHED=0;
  1189.     /* int OUT=0; */
  1190.     uchar *lastout;
  1191.     uchar *qx;
  1192.     uchar *px;
  1193.     int j;
  1194.     int DOWITHMASK;
  1195.  
  1196.     DOWITHMASK = 0;
  1197.     if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1198.     textend = text + end;
  1199.     lastout = text + start;
  1200.     textbegin = text + start;
  1201.     text = text + start - 1 ;
  1202. /*
  1203.     if (WORDBOUND || WHOLELINE) text = text-1;
  1204. */
  1205.     if (WHOLELINE) text = text-1;
  1206.         /* to accomodate the extra 2 W_delim */
  1207.     while (++text <= textend) {
  1208.         CurrentByteOffset ++;
  1209.         p = HASH[tr[*text]];
  1210.         p_end = HASH[tr[*text]+1];
  1211.         while(p++ < p_end) {
  1212.             if (((pat_index = pat_indices[p]) <= 0) || (pat_len[pat_index] <= 0)) continue;
  1213. #ifdef    debug
  1214.             printf("m_short(): p=%d pat_index=%d off=%d\n", p, pat_index, textend - text);
  1215. #endif
  1216.             px = PatPtr[p];
  1217.             qx = text;
  1218.             while((*px!=0)&&(tr[*px] == tr[*qx])) {
  1219.                 px++;
  1220.                 qx++;
  1221.             }
  1222.             if (*px == 0) {
  1223.                 if(text >= textend) return;
  1224.                 if (WORDBOUND) {
  1225.                     if (isalnum(*qx)) goto skip_output;
  1226.                     if (isalnum(*(text-1))) goto skip_output;
  1227.                 }
  1228.                                 if (!DOWITHMASK) {
  1229.                                         /* Don't update CurrentByteOffset here: only before outputting properly */
  1230.                                         if (!DELIMITER) {
  1231.                         curtextbegin = text; while((curtextbegin > textbegin) && (*(--curtextbegin) != '\n'));
  1232.                         if (*curtextbegin == '\n') curtextbegin ++;
  1233.                         curtextend = text+1; while((curtextend < textend) && (*curtextend != '\n')) curtextend ++;
  1234.                         if (*curtextend == '\n') curtextend ++;
  1235.                                         }
  1236.                                         else {
  1237.                                                 curtextbegin = backward_delimiter(text, textbegin, D_pattern, D_length, OUTTAIL);
  1238.                                                 curtextend = forward_delimiter(text+1, textend, D_pattern, D_length, OUTTAIL);
  1239.                                         }
  1240.                     if (!OUTTAIL || INVERSE) textbegin = curtextend;
  1241.                     else if (DELIMITER) textbegin = curtextend - D_length;
  1242.                     else textbegin = curtextend - 1;
  1243.                                 }
  1244.                                 /* else prev curtextbegin is OK: if full AND isn't found, DOWITHMASK is 0-ed so that we search at most 1 line below */
  1245.                 DOWITHMASK = 1;
  1246.  
  1247.                 amatched_terminals[pat_index - 1] = 1;
  1248.                 if (AComplexBoolean) {
  1249.                     /* Can output only after all the matches in the current record have been identified: just like filter_output */
  1250.                     oldtext = text;
  1251.                     CurrentByteOffset += (oldtext + pat_len[pat_index] - 1 - text);
  1252.                     text = oldtext + pat_len[pat_index] - 1;
  1253.                     MATCHED = 0;
  1254.                     goto skip_output;
  1255.                 }
  1256.                 else if ((long)AParse & AND_EXP) {
  1257.                     for (j=0; j<anum_terminals; j++) if (!amatched_terminals[j]) break;
  1258.                     if (j<anum_terminals) goto skip_output;
  1259.                 }
  1260.  
  1261.                 MATCHED = 1;
  1262.                 oldtext = text; /* used only if MULTI_OUTPUT */
  1263.  
  1264. #undef    DO_OUTPUT
  1265. #define DO_OUTPUT(change_text)\
  1266.                 num_of_matched++;\
  1267.                 if(FILENAMEONLY || SILENT)  return;\
  1268.                 if (!COUNT) {\
  1269.                     print_options(pat_index);\
  1270.                     if(!INVERSE) {\
  1271.                         if (agrep_finalfp != NULL) {\
  1272.                             fwrite(curtextbegin, 1, curtextend - curtextbegin, agrep_finalfp);\
  1273.                         }\
  1274.                         else {\
  1275.                             if (agrep_outpointer + curtextend - curtextbegin >= agrep_outlen) {\
  1276.                                 OUTPUT_OVERFLOW;\
  1277.                                 return -1;\
  1278.                             }\
  1279.                             else {\
  1280.                                 memcpy(agrep_outbuffer + agrep_outpointer, curtextbegin, curtextend-curtextbegin);\
  1281.                                 agrep_outpointer += curtextend - curtextbegin;\
  1282.                             }\
  1283.                         }\
  1284.                                                 if ((change_text) && MULTI_OUTPUT) {     /* next match starting from end of current */\
  1285.                             CurrentByteOffset += (oldtext + pat_len[pat_index] - 1 - text);\
  1286.                                                         text = oldtext + pat_len[pat_index] - 1;\
  1287.                                                         MATCHED = 0;\
  1288.                                                 }\
  1289.                         else if (change_text) {\
  1290.                             CurrentByteOffset += textbegin - text;\
  1291.                             text = textbegin;\
  1292.                         }\
  1293.                     }\
  1294.                     else {\
  1295.                                                 /* if(lastout < curtextbegin) OUT=1; */\
  1296.                         if (agrep_finalfp != NULL)\
  1297.                             fwrite(lastout, 1, curtextbegin-lastout, agrep_finalfp);\
  1298.                         else {\
  1299.                             if (curtextbegin - lastout + agrep_outpointer >= agrep_outlen) {\
  1300.                                 OUTPUT_OVERFLOW;\
  1301.                                 return -1;\
  1302.                             }\
  1303.                             memcpy(agrep_outbuffer+agrep_outpointer, lastout, curtextbegin-lastout);\
  1304.                             agrep_outpointer += (curtextbegin-lastout);\
  1305.                         }\
  1306.                                                 lastout=textbegin;\
  1307.                         if (change_text) {\
  1308.                             CurrentByteOffset += textbegin - text;\
  1309.                             text = textbegin;\
  1310.                         }\
  1311.                     }\
  1312.                 }\
  1313.                 else if (change_text) {\
  1314.                     CurrentByteOffset += textbegin - text;\
  1315.                     text = textbegin;\
  1316.                 }\
  1317.                 if ((LIMITOUTPUT > 0) && (LIMITOUTPUT <= num_of_matched)) return 0;    /* done */\
  1318.  
  1319.                 DO_OUTPUT(1)
  1320.             }
  1321.  
  1322.         skip_output:
  1323.                         if(MATCHED && !MULTI_OUTPUT && !AComplexBoolean) break;     /* else look for more possible matches */
  1324.             if (DOWITHMASK && (text >= curtextend - 1)) {
  1325.                 DOWITHMASK = 0;
  1326.                 if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  1327.                     DO_OUTPUT(0)
  1328.                 }
  1329.                 if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1330.             }
  1331.         }
  1332.         /* If I found some match and I am about to cross over a delimiter, then set DOWITHMASK to 0 and zero out the amatched_terminals */
  1333.         if (DOWITHMASK && (text >= curtextend - 1)) {
  1334.             DOWITHMASK = 0;
  1335.             if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  1336.                 DO_OUTPUT(0)
  1337.             }
  1338.             if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1339.         }
  1340.         if (MATCHED) text --;
  1341.         MATCHED = 0;
  1342.     } /* while */
  1343.     CurrentByteOffset ++;
  1344.  
  1345.     /* Do residual stuff: check if there was a match at the end of the line | check if rest of the buffer needs to be output due to inverse */
  1346.  
  1347.     if (DOWITHMASK && (text >= curtextend - 1)) {
  1348.         DOWITHMASK = 0;
  1349.         if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  1350.             DO_OUTPUT(0)
  1351.         }
  1352.         if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1353.     }
  1354.  
  1355.         if(INVERSE && !COUNT && (lastout <= textend)) {
  1356.                 if (agrep_finalfp != NULL) {
  1357.                         while(lastout <= textend) fputc(*lastout++, agrep_finalfp);
  1358.                 }
  1359.                 else {
  1360.                         if (textend - lastout + 1 + agrep_outpointer >= agrep_outlen) {
  1361.                                 OUTPUT_OVERFLOW;
  1362.                                 return -1;
  1363.                         }
  1364.                         memcpy(agrep_outbuffer+agrep_outpointer, lastout, text-lastout+1);
  1365.                         agrep_outpointer += (text-lastout+1);
  1366.                         lastout = textend;
  1367.                 }
  1368.         }
  1369.  
  1370.         return 0;
  1371. }
  1372.  
  1373. #if    DOTCOMPRESSED
  1374. /* shift is always 1: slight change in MATCHED semantics: it is set to 1 even if COUNT is set: previously, it wasn't set. Will it effect m_short? */
  1375. tc_m_short(text, start, end)
  1376. int start, end; register uchar *text;
  1377. {
  1378.     int pat_index;
  1379.         unsigned char *oldtext;
  1380.     register uchar *textend;
  1381.     unsigned char *textbegin;
  1382.     unsigned char *curtextend;
  1383.     unsigned char *curtextbegin;
  1384.     register int p, p_end;
  1385.     int MATCHED=0;
  1386.     /* int OUT=0; */
  1387.     uchar *lastout;
  1388.     uchar *qx;
  1389.     uchar *px;
  1390.     int j;
  1391.     int DOWITHMASK;
  1392.     struct timeval initt, finalt;
  1393.     int newlen;
  1394.  
  1395.     DOWITHMASK = 0;
  1396.     if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1397.     textend = text + end;
  1398.     lastout = text + start;
  1399.     text = text + start - 1 ;
  1400.     textbegin = text + start;
  1401.     /* WORDBOUND adjustment not required */
  1402.     while (++text <= textend) {
  1403.         CurrentByteOffset ++;
  1404.         p = tc_HASH[tc_tr[*text]];
  1405.         p_end = tc_HASH[tc_tr[*text]+1];
  1406.         while(p++ < p_end) {
  1407.             if (((pat_index = tc_pat_indices[p]) <= 0) || (tc_pat_len[pat_index] <= 0)) continue;
  1408. #ifdef    debug
  1409.             printf("m_short(): p=%d pat_index=%d off=%d\n", p, pat_index, textend - text);
  1410. #endif
  1411.             px = tc_PatPtr[p];
  1412.             qx = text;
  1413.             while((*px!=0)&&(tc_tr[*px] == tc_tr[*qx])) {
  1414.                 px++;
  1415.                 qx++;
  1416.             }
  1417.             if (*px == 0) {
  1418.                 if(text >= textend) return;
  1419.  
  1420.                 if (!DOWITHMASK) {
  1421.                     /* Don't update CurrentByteOffset here: only before outputting properly */
  1422.                     if (!DELIMITER) {
  1423.                         curtextbegin = text; while((curtextbegin > textbegin) && (*(--curtextbegin) != '\n'));
  1424.                         if (*curtextbegin == '\n') curtextbegin ++;
  1425.                         curtextend = text+1; while((curtextend < textend) && (*curtextend != '\n')) curtextend ++;
  1426.                         if (*curtextend == '\n') curtextend ++;
  1427.                     }
  1428.                     else {
  1429.                         curtextbegin = backward_delimiter(text, textbegin, tc_D_pattern, tc_D_length, OUTTAIL);
  1430.                         curtextend = forward_delimiter(text+1, textend, tc_D_pattern, tc_D_length, OUTTAIL);
  1431.                     }
  1432.                 }
  1433.                 /* else prev curtextbegin is OK: if full AND isn't found, DOWITHMASK is 0-ed so that we search at most 1 line below */
  1434. #if    MEASURE_TIMES
  1435.                 gettimeofday(&initt, NULL);
  1436. #endif    /*MEASURE_TIMES*/
  1437.                 /* Was it really a match in the compressed line from prev line in text to text + strlen(tc_pat_len[pat_index]? */
  1438.                 if (-1 == exists_tcompressed_word(tc_PatPtr[p], tc_pat_len[pat_index], curtextbegin, text - curtextbegin + tc_pat_len[pat_index], EASYSEARCH))
  1439.                     goto skip_output;
  1440. #if     MEASURE_TIMES
  1441.                 gettimeofday(&finalt, NULL);
  1442.                 FILTERALGO_ms +=  (finalt.tv_sec *1000 + finalt.tv_usec/1000) - (initt.tv_sec*1000 + initt.tv_usec/1000);
  1443. #endif  /*MEASURE_TIMES*/
  1444.  
  1445.                 if (!DOWITHMASK) {
  1446.                     if (!OUTTAIL || INVERSE) textbegin = curtextend;
  1447.                     else if (DELIMITER) textbegin = curtextend - D_length;
  1448.                     else textbegin = curtextend - 1;
  1449.                 }
  1450.                 DOWITHMASK = 1;
  1451.                 amatched_terminals[pat_index-1] = 1;
  1452.                 if (AComplexBoolean) {
  1453.                     /* Can output only after all the matches in the current record have been identified: just like filter_output */
  1454.                     oldtext = text;
  1455.                     CurrentByteOffset += (oldtext + pat_len[pat_index] - 1 - text);
  1456.                     text = oldtext + pat_len[pat_index] - 1;
  1457.                     MATCHED = 0;
  1458.                     goto skip_output;
  1459.                 }
  1460.                 else if ((long)AParse & AND_EXP) {
  1461.                     for (j=0; j<anum_terminals; j++) if (!amatched_terminals[j]) break;
  1462.                     if (j<anum_terminals) goto skip_output;
  1463.                 }
  1464.  
  1465.                 MATCHED = 1;
  1466.                 oldtext = text; /* used only if MULTI_OUTPUT */
  1467.  
  1468. #undef    DO_OUTPUT
  1469. #define DO_OUTPUT(change_text)\
  1470.                 num_of_matched++;\
  1471.                 if(FILENAMEONLY || SILENT)  return;\
  1472.                 if (!COUNT) {\
  1473.                     print_options(pat_index);\
  1474.                     if(!INVERSE) {\
  1475. /* #if     MEASURE_TIMES\
  1476.                         gettimeofday(&initt, NULL);\
  1477. #endif  MEASURE_TIMES*/\
  1478.                         if (agrep_finalfp != NULL)\
  1479.                             newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, curtextbegin, curtextend-curtextbegin, agrep_finalfp, -1, EASYSEARCH);\
  1480.                         else {\
  1481.                             if ((newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, curtextbegin, curtextend-curtextbegin, agrep_outbuffer, agrep_outlen - agrep_outpointer, EASYSEARCH)) > 0) {\
  1482.                                 if (newlen + agrep_outpointer >= agrep_outlen) {\
  1483.                                     OUTPUT_OVERFLOW;\
  1484.                                     return -1;\
  1485.                                 }\
  1486.                                 agrep_outpointer += newlen;\
  1487.                             }\
  1488.                         }\
  1489. /*#if     MEASURE_TIMES\
  1490.                         gettimeofday(&finalt, NULL);\
  1491.                         OUTFILTER_ms +=  (finalt.tv_sec* 1000 + finalt.tv_usec/1000) - (initt.tv_sec*1000 + initt.tv_usec/1000);\
  1492. #endif  MEASURE_TIMES*/\
  1493.                         if ((change_text) && MULTI_OUTPUT) {     /* next match starting from end of current */\
  1494.                             CurrentByteOffset += (oldtext + tc_pat_len[pat_index] - 1 - text);\
  1495.                             text = oldtext + tc_pat_len[pat_index] - 1;\
  1496.                             MATCHED = 0;\
  1497.                         }\
  1498.                         else if (change_text) {\
  1499.                             CurrentByteOffset += textbegin - text;\
  1500.                             text = textbegin;\
  1501.                         }\
  1502.                     }\
  1503.                     else {    /* INVERSE: Don't care about filtering time */\
  1504.                         /* if(lastout < curtextbegin) OUT=1; */\
  1505.                         if (agrep_finalfp != NULL)\
  1506.                             newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, lastout, curtextbegin - lastout, agrep_finalfp, -1, EASYSEARCH);\
  1507.                         else {\
  1508.                             if ((newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, lastout, curtextbegin - lastout, agrep_outbuffer, agrep_outlen - agrep_outpointer, EASYSEARCH)) > 0) {\
  1509.                                 if (newlen + agrep_outpointer >= agrep_outlen) {\
  1510.                                     OUTPUT_OVERFLOW;\
  1511.                                     return -1;\
  1512.                                 }\
  1513.                                 agrep_outpointer += newlen;\
  1514.                             }\
  1515.                         }\
  1516.                         lastout=textbegin;\
  1517.                         if (change_text) {\
  1518.                             CurrentByteOffset += textbegin - text;\
  1519.                             text = textbegin;\
  1520.                         }\
  1521.                     }\
  1522.                 }\
  1523.                 else if (change_text) {\
  1524.                     CurrentByteOffset += textbegin - text;\
  1525.                     text = textbegin;\
  1526.                 }\
  1527.                 if ((LIMITOUTPUT > 0) && (LIMITOUTPUT <= num_of_matched)) return 0;    /* done */\
  1528.  
  1529.                 DO_OUTPUT(1)
  1530.             }
  1531.  
  1532.         skip_output:
  1533.                         if(MATCHED && !MULTI_OUTPUT && !AComplexBoolean) break;     /* else look for more possible matches */
  1534.             if (DOWITHMASK && (text >= curtextend - 1)) {
  1535.                 DOWITHMASK = 0;
  1536.                 if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  1537.                     DO_OUTPUT(0)
  1538.                 }
  1539.                 if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1540.             }
  1541.         }
  1542.         /* If I found some match and I am about to cross over a delimiter, then set DOWITHMASK to 0 and zero out the amatched_terminals */
  1543.         if (DOWITHMASK && (text >= curtextend - 1)) {
  1544.             DOWITHMASK = 0;
  1545.             if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  1546.                 DO_OUTPUT(0)
  1547.             }
  1548.             if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1549.         }
  1550.         if (MATCHED) text--;
  1551.         MATCHED = 0;
  1552.     } /* while */
  1553.     CurrentByteOffset ++;
  1554.  
  1555.     /* Do residual stuff: check if there was a match at the end of the line | check if rest of the buffer needs to be output due to inverse */
  1556.  
  1557.     if (DOWITHMASK && (text >= curtextend - 1)) {
  1558.         DOWITHMASK = 0;
  1559.         if (AComplexBoolean && dd(curtextbegin, curtextend) && eval_tree(AParse, amatched_terminals)) {
  1560.             DO_OUTPUT(0)
  1561.         }
  1562.         if (AParse != 0) memset(amatched_terminals, '\0', anum_terminals);
  1563.     }
  1564.  
  1565.     if (INVERSE && !COUNT && (lastout <= textend)) {
  1566.         if (agrep_finalfp != NULL)
  1567.             newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, lastout, textend - lastout + 1, agrep_finalfp, -1, EASYSEARCH);
  1568.         else {
  1569.             if ((newlen = quick_tuncompress(FREQ_FILE, STRING_FILE, lastout, textend - lastout + 1, agrep_outbuffer, agrep_outlen - agrep_outpointer, EASYSEARCH)) > 0) {
  1570.                 if (newlen + agrep_outpointer >= agrep_outlen) {
  1571.                     OUTPUT_OVERFLOW;
  1572.                     return -1;
  1573.                 }
  1574.                 agrep_outpointer += newlen;
  1575.             }
  1576.         }
  1577.     }
  1578.  
  1579.         return 0;
  1580. }
  1581. #endif    /*DOTCOMPRESSED*/
  1582.  
  1583. f_prep(pat_index, Pattern)
  1584. uchar *Pattern;   int pat_index;
  1585. {
  1586. int i, m;
  1587. register unsigned hash=0;
  1588. #ifdef debug
  1589.     puts(Pattern);
  1590. #endif
  1591.     m = p_size;
  1592.         for (i=m-1; i>=(1+LONG); i--) {
  1593.                 hash = (tr1[Pattern[i]]);
  1594.                 hash = (hash << Hbits) + (tr1[Pattern[i-1]]);
  1595.         if(LONG) hash = (hash << Hbits) + (tr1[Pattern[i-2]] );
  1596.         if(SHIFT1[hash] >= m-1-i) SHIFT1[hash] = m-1-i;
  1597.     }
  1598.     i=m-1;
  1599.         hash = (tr1[Pattern[i]]);
  1600.         hash = (hash << Hbits) + (tr1[Pattern[i-1]]);
  1601.     if(LONG) hash = (hash << Hbits) + (tr1[Pattern[i-2]] );
  1602.         if(SHORT) hash=tr[Pattern[0]];
  1603. #ifdef debug
  1604.     printf("hash = %d\n", hash);
  1605. #endif
  1606.         HASH[hash]++;
  1607.         return;
  1608. }
  1609.  
  1610. #if    DOTCOMPRESSED
  1611. tc_f_prep(pat_index, Pattern)
  1612. uchar *Pattern;   int pat_index;
  1613. {
  1614. int i, m;
  1615. register unsigned hash=0;
  1616. #ifdef debug
  1617.     puts(Pattern);
  1618. #endif
  1619.     m = tc_p_size;
  1620.         for (i=m-1; i>=(1+tc_LONG); i--) {
  1621.                 hash = (tc_tr1[Pattern[i]]);
  1622.                 hash = (hash << Hbits) + (tc_tr1[Pattern[i-1]]);
  1623.         if(tc_LONG) hash = (hash << Hbits) + (tc_tr1[Pattern[i-2]] );
  1624.         if(tc_SHIFT1[hash] >= m-1-i) tc_SHIFT1[hash] = m-1-i;
  1625.     }
  1626.     i=m-1;
  1627.         hash = (tc_tr1[Pattern[i]]);
  1628.         hash = (hash << Hbits) + (tc_tr1[Pattern[i-1]]);
  1629.     if(tc_LONG) hash = (hash << Hbits) + (tc_tr1[Pattern[i-2]] );
  1630.         if(tc_SHORT) hash=tc_tr[Pattern[0]];
  1631. #ifdef debug
  1632.     printf("hash = %d\n", hash);
  1633. #endif
  1634.         tc_HASH[hash]++;
  1635.         return;
  1636. }
  1637. #endif    /*DOTCOMPRESSED*/
  1638.  
  1639. f_prep1(pat_index, Pattern)
  1640. uchar *Pattern;   int pat_index;
  1641. {
  1642. int i, m;
  1643. int hash2;
  1644. register unsigned hash;
  1645.     m = p_size;
  1646. #ifdef debug
  1647.     puts(Pattern);
  1648. #endif
  1649.         for (i=m-1; i>=(1+LONG); i--) {
  1650.                 hash = (tr1[Pattern[i]]);
  1651.                 hash = (hash << Hbits) + (tr1[Pattern[i-1]]);
  1652.         if(LONG) hash = (hash << Hbits) + (tr1[Pattern[i-2]] );
  1653.         if(SHIFT1[hash] >= m-1-i) SHIFT1[hash] = m-1-i;
  1654.     }
  1655.     i=m-1;
  1656.         hash = (tr1[Pattern[i]]);
  1657.         hash = (hash << Hbits) + (tr1[Pattern[i-1]]);
  1658.     if(LONG) hash = (hash << Hbits) + (tr1[Pattern[i-2]] );
  1659.         if(SHORT) hash=tr[Pattern[0]];
  1660.     hash2 = (tr[Pattern[0]] << 8) + tr[Pattern[1]];
  1661. #ifdef debug
  1662.     printf("hash = %d, HASH[hash] = %d\n", hash, HASH[hash]);
  1663. #endif
  1664.         PatPtr[HASH[hash]] = Pattern;
  1665.         pat_indices[HASH[hash]] = pat_index;
  1666.     Hash2[HASH[hash]] = hash2;
  1667.         HASH[hash]--;
  1668.         return;
  1669. }
  1670.  
  1671. #if    DOTCOMPRESSED
  1672. tc_f_prep1(pat_index, Pattern)
  1673. uchar *Pattern;   int pat_index;
  1674. {
  1675. int i, m;
  1676. int hash2;
  1677. register unsigned hash;
  1678.     m = tc_p_size;
  1679. #ifdef debug
  1680.     puts(Pattern);
  1681. #endif
  1682.         for (i=m-1; i>=(1+tc_LONG); i--) {
  1683.                 hash = (tc_tr1[Pattern[i]]);
  1684.                 hash = (hash << Hbits) + (tc_tr1[Pattern[i-1]]);
  1685.         if(tc_LONG) hash = (hash << Hbits) + (tc_tr1[Pattern[i-2]] );
  1686.         if(tc_SHIFT1[hash] >= m-1-i) tc_SHIFT1[hash] = m-1-i;
  1687.     }
  1688.     i=m-1;
  1689.         hash = (tc_tr1[Pattern[i]]);
  1690.         hash = (hash << Hbits) + (tc_tr1[Pattern[i-1]]);
  1691.     if(tc_LONG) hash = (hash << Hbits) + (tc_tr1[Pattern[i-2]] );
  1692.         if(tc_SHORT) hash=tc_tr[Pattern[0]];
  1693.     hash2 = (tc_tr[Pattern[0]] << 8) + tc_tr[Pattern[1]];
  1694. #ifdef debug
  1695.     printf("hash = %d, tc_HASH[hash] = %d\n", hash, tc_HASH[hash]);
  1696. #endif
  1697.         tc_PatPtr[tc_HASH[hash]] = Pattern;
  1698.         tc_pat_indices[tc_HASH[hash]] = pat_index;
  1699.     tc_Hash2[tc_HASH[hash]] = hash2;
  1700.         tc_HASH[hash]--;
  1701.         return;
  1702. }
  1703. #endif    /*DOTCOMPRESSED*/
  1704.  
  1705. accumulate()
  1706. {
  1707.     int i;
  1708.  
  1709.     for(i=1; i<MAXHASH; i++)  {
  1710.     /*
  1711.     printf("%d, ", HASH[i]);
  1712.     */
  1713.     HASH[i] = HASH[i-1] + HASH[i];
  1714.     }
  1715.     HASH[0] = 0;
  1716.     return;
  1717. }
  1718.  
  1719. #if    DOTCOMPRESSED
  1720. tc_accumulate()
  1721. {
  1722.     int i;
  1723.  
  1724.     for(i=1; i<MAXHASH; i++)  {
  1725.     /*
  1726.     printf("%d, ", HASH[i]);
  1727.     */
  1728.     tc_HASH[i] = tc_HASH[i-1] + tc_HASH[i];
  1729.     }
  1730.     tc_HASH[0] = 0;
  1731.     return;
  1732. }
  1733. #endif    /*DOTCOMPRESSED*/
  1734.  
  1735.  
  1736.